#include <QTextCodec>
#include <QDataStream>
#include <QFile>
#include <QTimer>
#include <QPaintEvent>
#include <QPainter>
#include <QImage>
#include <QMessageBox>
#if defined(Q_OS_WIN32)
#include <WinSock2.h>
#elif defined(Q_OS_LINUX)
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include <xvid.h>
#include <QThread>
#include <QSemaphore>

#if INDOOREMBED
#include <QDirectPainter>
#endif

#include "maindialog.h"
#include "devicedetaildialog.h"
#include "ui_maindialog.h"

#define NODECOUNT 64
VideoNode_t videonode[NODECOUNT];
pVideoNode pWriteVideoHeader;//环形缓冲区写标志
pVideoNode pReadVideoHeader;//环形缓冲区写标志
int video_node_count=0;//视频节点个数(存量)

#define PAINT_IMAGE_DIRECTFB    0 //直接写framebuffer
#define PAINT_IMAGE_QIMAGE      1 //直接写QImage控件
#define PAINT_IMAGE_MODE        PAINT_IMAGE_DIRECTFB //写QImage控件

#define LINK_STATIC     0
#define LINK_DYNAMIC    1
#define LINK            LINK_STATIC

#define SCREEN_WIDTH    352
#define SCREEN_HEIGHT   240

#define C_WIDTH   352
#define C_HEIGHT  240
#define C_SCREEN_SIZE  C_WIDTH * C_HEIGHT * 3

uchar decode_data[352*240*4];

#if (LINK==LINK_DYNAMIC)
static void *dllHandle=NULL;
typedef int(*XVID_PROTO) (void *handle, int opt,  void *param1, void *param2);
static XVID_PROTO xvid_global_func   = NULL;
static XVID_PROTO xvid_encore_func = NULL;
static XVID_PROTO xvid_decore_func = NULL;
#elif (LINK==LINK_STATIC)
#define xvid_global_func  xvid_global
#define xvid_encore_func  xvid_encore
#define xvid_decore_func  xvid_decore
#endif

int devfb0;
char * fb0;
int Position = 0;
FILE * fp;
char * error;
xvid_dec_create_t xVid_decode;
xvid_dec_frame_t  xvid_decFrame;
xvid_dec_stats_t  xvid_decStats;
xvid_gbl_init_t   xvid_gbl;
int xvid_Version;

//char FrameA[C_WIDTH * C_HEIGHT * 3];
//char FrameC[C_WIDTH * C_HEIGHT * 3];
int Ret;
//char buff[1089173];

QSemaphore semUDPRecv(0);
QSemaphore semDecode(0);

#if (PAINT_IMAGE_MODE==PAINT_IMAGE_QIMAGE)
QImage *qimage;// = new QImage(352, 240, QImage::Format_RGB888);
#endif

void init_xvid_codec()
{
    printf("init_xvid_codec    1111111111111111 \n");
#ifdef Q_WS_X11
#if (LINK==LINK_DYNAMIC)
         dllHandle = dlopen("libxvidcore.so", RTLD_NOW);
    if(!dllHandle)
    {
        printf("libxvidcore.so 加载失败\n");
        //return 0;
    }
    else
    {
        printf("libxvidcore.so 加载正常!\n");
    }

    xvid_global_func = (XVID_PROTO)dlsym(dllHandle, "xvid_global");
    xvid_decore_func = (XVID_PROTO)dlsym(dllHandle, "xvid_decore");
    xvid_encore_func = (XVID_PROTO)dlsym(dllHandle, "xvid_encore");

    if ((error = dlerror()) != NULL)
    {
        fputs(error, stderr);
        printf("加载函数失败.....\n");
    }
    else
    {
        printf("正常加载函数!.........\n");
    }
#endif
#endif
printf("init_xvid_codec    2222222222222222222 \n");
      xvid_Version = XVID_MAKE_VERSION(1, 1, 0);
      printf("init_xvid_codec    33333333333 \n");

    xvid_gbl.version = xvid_Version;
    printf("init_xvid_codec    444444444 \n");

    xvid_gbl.cpu_flags = (XVID_CPU_FORCE | XVID_CPU_ASM);
    printf("init_xvid_codec    55555555 \n");

    xvid_gbl.debug = 0;
    printf("init_xvid_codec    666666666 \n");

    xvid_global_func(NULL, XVID_GBL_INIT, &xvid_gbl, NULL);

printf("init_xvid_codec    777777777777 \n");
    xVid_decode.version = xvid_Version;
    xVid_decode.width = C_WIDTH;
    xVid_decode.height = C_HEIGHT;
    printf("init_xvid_codec    88888888 \n");

    xvid_decore_func(NULL, XVID_DEC_CREATE, &xVid_decode, NULL);
printf("init_xvid_codec    999999999999 \n");
}

//视频节点初始化
void init_node()
{
    printf("init_node 11111111111111111 \n");
	for(int i=0;i<NODECOUNT-1;i++)
	{
		videonode[i].Position = 0;
		videonode[i].pnext = &(videonode[i+1]);
	}
    printf("init_node 222222222222 \n");

	videonode[NODECOUNT-1].Position = 0;
	videonode[NODECOUNT-1].pnext = &(videonode[0]);
	pWriteVideoHeader = &(videonode[0]);
	pReadVideoHeader = &(videonode[0]);
    printf("init_node 33333333333333 \n");

}


using namespace std;
#include <iostream>

//监视时发送在线确认
void UDPRecvThread::online_check()
{
    QByteArray datagram; //拥于存放接收的数据报
    datagram.resize(61);
    datagram.clear();
#if QT_VERSION <= 0x040500 //QT 4.5版本无 insert(int i, const char *s, int len);
    datagram.insert(0, "XXXCID");
#else
    datagram.insert(0, "XXXCID", 6);
#endif
    datagram[6] = char(0x98);//watch
    datagram[7] = char(0x01);//主动发送
    datagram[8] = char(0x09);//在线确认
#if QT_VERSION <= 0x040500 //QT 4.5版本无 insert(int i, const char *s, int len);
    datagram.insert(9, "S00010101010");
#else
    datagram.insert(9, "S00010101010", 12);
#endif
    datagram[29] = char(192);
    datagram[30] = char(168);
    datagram[31] = char(68);
    datagram[32] = char(233);
#if QT_VERSION <= 0x040500 //QT 4.5版本无 insert(int i, const char *s, int len);
    datagram.insert(33, "M00010100000");
#else
    datagram.insert(33, "M00010100000", 12);
#endif
    datagram[53] = char(192);
    datagram[54] = char(168);
    datagram[55] = char(68);
    datagram[56] = char(143);
    datagram[57] = char(0);
    datagram[58] = char(0);
    datagram[59] = char(0);
    datagram[60] = char(5);
    QHostAddress dest_addr("192.168.68.143");
    udpVideoSocket->writeDatagram(datagram.data(),61, dest_addr, 8302);
}

//udp收到视频数据
void UDPRecvThread::processVideoDatagrams()
{
    while(udpVideoSocket->hasPendingDatagrams())
    {
        //printf("recv %d bytes\n", udpVideoSocket->pendingDatagramSize());
        //outfile->write("xxxxy", 5);
        QByteArray datagram; //拥于存放接收的数据报
        datagram.resize(udpVideoSocket->pendingDatagramSize());
        //让datagram的大小为等待处理的数据报的大小，这样才能接收到完整的数据
        udpVideoSocket->readDatagram(datagram.data(),datagram.size());

        if(datagram.size() > 73)
        {
            pData pdata = (pData)(datagram.data());
            //char order = datagram.at(6);
            //char pi_frame = datagram.at(61);
            //char video = datagram.at(8);
            if((pdata->header.Order == (unsigned char)0x98) || (pdata->header.Order == (unsigned char)0x99))//watch 数据
            {
                if(pdata->talkdata.SubOrder == (unsigned char)0x08)//视频
                {
                    if(pdata->talkdata.DataType == (unsigned char)0x01) //音频数据
                    {
                        //printf("audio package\n");
#if DEBUG==1
                        outfile_audio->write(&(pdata->talkdata.AVdata), 128);//datagram.size()-sizeof(tagData)+1);
#endif

#if 0
                        short * pcm = (short*)malloc(sizeof(short)*128);
                        G711Decoder(pcm, (unsigned char*)(&(pdata->talkdata.AVdata)), 128, 1);
                        iodevice->write((char*)pcm, 256);
                        free(pcm);
#endif
                    }
                    else if((pdata->talkdata.DataType == (char)0x02) || (pdata->talkdata.DataType == (char)0x03))//I帧 或 P帧
                    {
                        //printf("video package\n");
                        //printf("");
                        //char * pRecvData = &(datagram.data()[77]);
                        //outfile->write(pRecvData, datagram.size()-77);
                        //outfile->write(&(pdata->talkdata.AVdata), datagram.size()-77);
#if DEBUG==1
                        outfile_video->write(&(pdata->talkdata.AVdata), datagram.size()-sizeof(tagData)+1);
#endif
#if DEBUG==0
                        pWriteVideoHeader->Frameno = pdata->talkdata.Frameno;
                        pWriteVideoHeader->DataType = pdata->talkdata.DataType;
                        pWriteVideoHeader->Framelen = pdata->talkdata.Framelen;
                        pWriteVideoHeader->timestamp = pdata->talkdata.timestamp;
                        memcpy(&(pWriteVideoHeader->videodata[pWriteVideoHeader->Position]), &(pdata->talkdata.AVdata), datagram.size()-sizeof(tagData)+1);
                        pWriteVideoHeader->Position += datagram.size()-sizeof(tagData)+1;//指针游标位置
                        if(pdata->talkdata.CurrPackage == pdata->talkdata.TotalPackage)
                        {
                            video_node_count++;
                            pWriteVideoHeader = pWriteVideoHeader->pnext;
                            pWriteVideoHeader->Position = 0;
                            semUDPRecv.release(1);
                        }
#endif
#if DEBUG==1
                        QString str;
                        str.sprintf("DataType=%d,TotalPackage=%d, CurrPackage=%d, Datalen=%d, PackLen=%d, timestamp=%d,Frameno=%d,Framelen=%d",
                            pdata->talkdata.DataType, pdata->talkdata.TotalPackage, pdata->talkdata.CurrPackage, pdata->talkdata.Datalen,
                            pdata->talkdata.PackLen, pdata->talkdata.timestamp, pdata->talkdata.Frameno, pdata->talkdata.Framelen);
                        ui->textEdit->append(str);
#endif
                    }
                }
            }
        }
    }
}

UDPRecvThread::UDPRecvThread() {
    printf("Dialog dddddddddddddddddddddd  \n");

    QAudioFormat format;
    // Set up the format, eg.
    format.setFrequency(8000);
    format.setChannels(1);
    format.setSampleSize(16);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::UnSignedInt);
    printf("Dialog 22222222222222222  \n");

    QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
    if (!info.isFormatSupported(format)) {
        //qWarning()<<"raw audio format not supported by backend, cannot play audio.";
        printf("info.isFormatSupported(format) \n");
    }
    printf("Dialog 333333333333333333333  \n");

    audio = new QAudioOutput(format, this);
    iodevice = audio->start();
    stopped = false;
    this->name = name;
    udpVideoSocket = new QUdpSocket(this);
    port = 8302;
    udpVideoSocket->bind(port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
    printf("Dialog 9999999999999999999999  \n");
}

void UDPRecvThread::monitor(){
    //::MessageBox(NULL, TEXT("show"), TEXT("caption"), 0);//直接调用win32的api函数

    QByteArray datagram = "";
    datagram.resize(512);

    //this->remove_tableview_allrow();

    for(int i=7;i<datagram.size();i++)
    {
        datagram[i] = 0x00;
    }

#if QT_VERSION <= 0x040500 //QT 4.5版本无 insert(int i, const char *s, int len);
    datagram.insert(0, "XXXCID");
#else
    datagram.insert(0, "XXXCID", 6);
#endif
    datagram[6] = (char)(152);//VIDEO WATCH
    datagram[7] = 1;//ASK
    datagram[8] = 1;//CALL
#if QT_VERSION <= 0x040500 //QT 4.5版本无 insert(int i, const char *s, int len);
#else
    datagram.insert(9, "S00010101010", 12);//本机房号
#endif
    datagram[29] = (char)192;
    datagram[30] = (char)168;
    datagram[31] = (char)68;
    datagram[32] = (char)233;
#if QT_VERSION <= 0x040500 //QT 4.5版本无 insert(int i, const char *s, int len);
    datagram.insert(33, "M00010100000");
#else
    datagram.insert(33, "M00010100000", 12);
#endif
    datagram[53] = (char)192;
    datagram[54] = (char)168;
    datagram[55] = (char)68;
    datagram[56] = (char)143;
    datagram[17] = (char)0xFF;

    //datagram.set
    QHostAddress dest_addr("192.168.68.143");
    udpVideoSocket->writeDatagram(datagram.data(),62, dest_addr, 8302);
    //udpSocket->readDatagram();
}

void UDPRecvThread::run() {
    //online_check_timer = new QTimer(this);
    //online_check_timer->setInterval(1000);
    //connect(online_check_timer, SIGNAL(timeout()), this, SLOT(online_check()));
    //online_check_timer->start(1000);

    connect(udpVideoSocket, SIGNAL(readyRead()), this, SLOT(processVideoDatagrams()));
    this->monitor();
    //this->exec();

    while (!stopped) {
        cout << "In " << name.toStdString() << "'s run()." << std::endl;
        QThread::msleep(1000);
        online_check();
    }

}

void UDPRecvThread::stop() {
    stopped = true;
}


uchar *fb;

void AVDecodeThread::run() {
    extern Dialog *maindialog;
    while(1)
    {
        semUDPRecv.acquire();
        if(video_node_count > 0)
        {
            printf("in playVideo video_node_count=%d\n", video_node_count);
            video_node_count--;

            xvid_decFrame.version = xvid_Version;
            xvid_decFrame.general = 0;
            xvid_decFrame.bitstream = &(pReadVideoHeader->videodata);
            xvid_decFrame.length = C_SCREEN_SIZE;
            xvid_decFrame.output.csp = XVID_CSP_BGRA;
                //printf("main:5555555555555\n");

            xvid_decFrame.output.plane[0] = decode_data;
            xvid_decFrame.output.stride[0] = C_WIDTH * 4;
                //printf("main:6666666666666\n");
#if 1
            Ret = xvid_decore_func(xVid_decode.handle, XVID_DEC_DECODE, &xvid_decFrame, NULL);
#endif
                //Position += Ret;
             printf("Ret = %d, Position = %d .aaaaaa\n", Ret, Position);
             pReadVideoHeader = pReadVideoHeader->pnext;
#if (PAINT_IMAGE_MODE==PAINT_IMAGE_QIMAGE)
            memcpy(qimage->scanLine(0), decode_data, 352*240*4);
            //semDecode.release();
            //QThread::postEvent(w,  new QPaintEvent( rect(), false ));
            maindialog->update();

#endif

#if (PAINT_IMAGE_MODE==PAINT_IMAGE_DIRECTFB)
                int xLeft = 430;
                int yTop = 100;
            //uchar *fb1 = fb;
            //printf("fb = %d, %x\n", fb, fb);
            for(int i=0;i<240;i++)
                for(int j=0;j<352;j++)
            {
                    ((uint32_t*)fb)[(i+yTop)*800 + j + xLeft] = ((uint32_t*)decode_data)[i*352 + j];
            }
#endif
        }
    }

}

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
#if 0
    setAutoFillBackground(true);
    QPixmap pixmap("./image/talk.jpg");
    QPalette palette = this->palette();
    palette.setBrush(backgroundRole(), QBrush(pixmap));
    setPalette(palette);
#endif

#if (PAINT_IMAGE_MODE==PAINT_IMAGE_QIMAGE)
    qimage = new QImage(352, 240, QImage::Format_RGB32);
#endif

    QDirectPainter painter(this, QDirectPainter::NonReserved);
    //painter.startPainting(true);
    //painter.setRegion(QRegion(100, 100, 100, 100));
    fb = painter.frameBuffer();

#if INDOOREMBED
    setWindowFlags(Qt::FramelessWindowHint);//隐藏窗口标题栏
#endif

    printf("Dialog 111111111111111111111111  \n");


    printf("Dialog 444444444444444444444  \n");

	init_xvid_codec();
    printf("Dialog 444444aaaaaaaaaaaaaaaa  \n");

	init_node();
    printf("Dialog 4444444bbbbbbbbbbbbbb  \n");

#if DEBUG==1
	outfile_video = new QFile("test2_352x240.m4e");//录像文件
	outfile_video->open(QIODevice::WriteOnly);

	outfile_audio = new QFile("record_g711.pcm");//录音文件
  	outfile_audio->open(QIODevice::WriteOnly);
#endif
	//outfile->write("12345", 20);
	//outfile->write("2222", 2);
	//outfile->write("5555", 3);
	//outfile->close();
    printf("Dialog 5555555555555555  \n");
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("utf8"));
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf8"));
    QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8"));
    printf("Dialog 6666666666666666  \n");

    listcount = 0;//初始化列表机器数量
    udpSocket = new QUdpSocket(this);//创建一个QUdpSocket类对象，该类提供了Udp的许多相关操作
    port = 8300;
    //此处的bind是个重载函数，连接本机的port端口，采用ShareAddress模式(即允许其它的服务连接到相同的地址和端口，特别是
    //用在多客户端监听同一个服务器端口等时特别有效)，和ReuseAddressHint模式(重新连接服务器)
    udpSocket->bind(port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
    connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));

    printf("Dialog 88888888888888888888888  \n");

    //准备数据模型
    student_model = new QStandardItemModel();
    printf("student_model->rowCount()=%d\n", student_model->rowCount());
    student_model->setHorizontalHeaderItem(0, new QStandardItem(QObject::tr("序号")));
    printf("student_model->rowCount()=%d\n", student_model->rowCount());
    student_model->setHorizontalHeaderItem(1, new QStandardItem(QObject::tr("设备编号")));
    student_model->setHorizontalHeaderItem(2, new QStandardItem(QObject::tr("设备类型")));
    student_model->setHorizontalHeaderItem(3, new QStandardItem(QObject::tr("MAC地址")));
    student_model->setHorizontalHeaderItem(4, new QStandardItem(QObject::tr("IP地址")));
    student_model->setHorizontalHeaderItem(5, new QStandardItem(QObject::tr("子网掩码")));
    student_model->setHorizontalHeaderItem(6, new QStandardItem(QObject::tr("网关地址")));
    student_model->setHorizontalHeaderItem(7, new QStandardItem(QObject::tr("服务器地址")));
    student_model->setHorizontalHeaderItem(8, new QStandardItem(QObject::tr("机器描述")));
    printf("student_model->rowCount()=%d\n", student_model->rowCount());
    //利用setModel()方法将数据模型与QTableView绑定
    ui->tableView->setModel(student_model);

    printf("Dialog aaaaaaaaaaaaaaaaaaaaaaaaaaaa  \n");

    ui->tableView->horizontalHeader()->setResizeMode(0, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(1, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(2, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(3, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(4, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(5, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(6, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(7, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(8, QHeaderView::Fixed);
    //设置表格的各列的宽度值
    ui->tableView->setColumnWidth(0, 50);//序号
    ui->tableView->setColumnWidth(1,120);//机器编号
    ui->tableView->setColumnWidth(2, 80);//设备类型
    ui->tableView->setColumnWidth(3,130);//MAC
    ui->tableView->setColumnWidth(4,130);//IP
    ui->tableView->setColumnWidth(5,130);//MASK
    ui->tableView->setColumnWidth(6,130);//GateWay
    ui->tableView->setColumnWidth(7,130);//serverip
    ui->tableView->setColumnWidth(8,50);//description
    printf("Dialog bbbbbbbbbbbbbbbbbbbb  \n");

    //设置选中时为整行选中
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);

    //单元格禁止编辑
    ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);

    printf("Dialog ccccccccccccccccccccc  \n");

/*
	play_video_timer = new QTimer(this);
    play_video_timer->setInterval(20);
	connect(play_video_timer, SIGNAL(timeout()), this, SLOT(playVideo()));
	play_video_timer->start();
*/
    printf("Dialog eeeeeeeeeeeeeeeeeeeeeeeeee  \n");

}

Dialog::~Dialog()
{
    delete ui;
}

void Dialog::remove_tableview_allrow()//删除所有行
{
#if 0
    ui->tableView->reset();
#else
    printf("remove_tableview_allrow 11111111111111111111 \n");
    int row_count = student_model->rowCount();
    printf("remove_tableview_allrow 222222222222222 \n");

    for(int i=row_count-1;i>=0;i--)
    {
        printf("remove_tableview_allrow 4444444444444 \n");

        student_model->removeRow(i);
    }
    printf("remove_tableview_allrow 555555555555555 \n");

    listcount = 0;
#endif
}

#if 0
void Dialog::playVideo()
{    
	if(video_node_count > 0)
	{
        semUDPRecv.acquire();
        //printf("in playVideo\n");
		video_node_count--;
		
		xvid_decFrame.version = xvid_Version;
		xvid_decFrame.general = 0;
		xvid_decFrame.bitstream = &(pReadVideoHeader->videodata);
		xvid_decFrame.length = C_SCREEN_SIZE;
        xvid_decFrame.output.csp = XVID_CSP_RGBA;
			//printf("main:5555555555555\n");

			xvid_decFrame.output.plane[0] = decode_data;
        xvid_decFrame.output.stride[0] = C_WIDTH * 4;
			//printf("main:6666666666666\n");
		#if 1
		Ret = xvid_decore_func(xVid_decode.handle, XVID_DEC_DECODE, &xvid_decFrame, NULL);
		#endif
			//Position += Ret;
			printf("Ret = %d, Position = %d ... ...\n", Ret, Position);
			pReadVideoHeader = pReadVideoHeader->pnext;
        semDecode.release();
		update();
	}

}
#endif


void Dialog::processPendingDatagrams()
{
    //static int listcount = 0;
    while(udpSocket->hasPendingDatagrams())  //拥有等待的数据报
    {
        QByteArray datagram; //拥于存放接收的数据报
        datagram.resize(udpSocket->pendingDatagramSize());
        //让datagram的大小为等待处理的数据报的大小，这样才能接收到完整的数据
        udpSocket->readDatagram(datagram.data(),datagram.size());
        //接收数据报，将其存放到datagram中
        ui->textEdit->append(datagram);
        //将数据报内容显示出来

        if( (quint8)(datagram.data()[6]) == (quint8)0xAA)
        {            
            QString strOrder, strDeviceNO, strDeviceType, strMac, stripaddr, strmask, strgateway;
            QString strserverip, strDescription;
            strDeviceNO.sprintf("%s", &(datagram.data()[7]));//= new QString((char*)&datagram[7]);//设备编号
            //memcpy(strDeviceNO.data(), &datagram[7], 20);

            strOrder.sprintf("%d", listcount+1);

            if((datagram.data()[7]) == 'S')
            {
                strDeviceType.sprintf("室d内d");
            }
            else if((datagram.data()[7]) == 'M')
            {
                strDeviceType.sprintf("门口");
            }
            else if((datagram.data()[7]) == 'W')
            {
                strDeviceType.sprintf("围墙");
            }

            strMac.sprintf("%02x-%02x-%02x-%02x-%02x-%02x",
                           (quint8)datagram.data()[27], (quint8)datagram.data()[28], (quint8)datagram.data()[29],
                           (quint8)datagram.data()[30], (quint8)datagram.data()[31], (quint8)datagram.data()[32]);

            stripaddr.sprintf("%03d.%03d.%03d.%03d",
                              (quint8)datagram.data()[33], (quint8)datagram.data()[34],
                              (quint8)datagram.data()[35], (quint8)datagram.data()[36]);

            strmask.sprintf("%03d.%03d.%03d.%03d",
                              (quint8)datagram.data()[37], (quint8)datagram.data()[38],
                              (quint8)datagram.data()[39], (quint8)datagram.data()[40]);


            strgateway.sprintf("%03d.%03d.%03d.%03d",
                              (quint8)datagram.data()[41], (quint8)datagram.data()[42],
                              (quint8)datagram.data()[43], (quint8)datagram.data()[44]);

            strserverip.sprintf("%03d.%03d.%03d.%03d",
                                (quint8)datagram.data()[45], (quint8)datagram.data()[46],
                                (quint8)datagram.data()[47], (quint8)datagram.data()[48]);

            strDescription;
            //在第一行添加学生张三的个人信息(setItem函数的第一个参数表示行号，第二个表示列号，第三个为要显示的数据)
            student_model->setItem(listcount, 0, new QStandardItem(strOrder));
            student_model->setItem(listcount, 1, new QStandardItem(strDeviceNO));
            student_model->setItem(listcount, 2, new QStandardItem(strDeviceType));
            student_model->setItem(listcount, 3, new QStandardItem(strMac));
            student_model->setItem(listcount, 4, new QStandardItem(stripaddr));
            student_model->setItem(listcount, 5, new QStandardItem(strmask));
            student_model->setItem(listcount, 6, new QStandardItem(strgateway));
            student_model->setItem(listcount, 7, new QStandardItem(strserverip));
            student_model->setItem(listcount, 8, new QStandardItem(strDescription));
            listcount++;
        }
    }
}


void Dialog::on_pushButton_clicked()
{
    ui->textEdit->setPlainText("同学们好");

    //准备数据模型
    QStandardItemModel *student_model = new QStandardItemModel();
    student_model->setHorizontalHeaderItem(0, new QStandardItem(QObject::tr("Name")));
    student_model->setHorizontalHeaderItem(1, new QStandardItem(QObject::tr("NO.")));
    student_model->setHorizontalHeaderItem(2, new QStandardItem(QObject::tr("Sex")));
    student_model->setHorizontalHeaderItem(3, new QStandardItem(QObject::tr("Age")));
    student_model->setHorizontalHeaderItem(4, new QStandardItem(QObject::tr("College")));
    //利用setModel()方法将数据模型与QTableView绑定
    ui->tableView->setModel(student_model);



    ui->tableView->horizontalHeader()->setResizeMode(0, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(1, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(2, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(3, QHeaderView::Fixed);
    ui->tableView->horizontalHeader()->setResizeMode(4, QHeaderView::Fixed);
    //设置表格的各列的宽度值
    ui->tableView->setColumnWidth(0,100);
    ui->tableView->setColumnWidth(1,100);
    ui->tableView->setColumnWidth(2,100);
    ui->tableView->setColumnWidth(3,100);
    ui->tableView->setColumnWidth(4,100);

    //默认显示行头，如果你觉得不美观的话，我们可以将隐藏
    ui->tableView->verticalHeader()->hide();
    //设置选中时为整行选中
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);

    //在第一行添加学生张三的个人信息(setItem函数的第一个参数表示行号，第二个表示列号，第三个为要显示的数据)
    student_model->setItem(0, 0, new QStandardItem("张三"));
    student_model->setItem(0, 1, new QStandardItem("20120202"));
    student_model->setItem(0, 2, new QStandardItem(""));
    student_model->setItem(0, 3, new QStandardItem("18"));
    student_model->setItem(0, 4, new QStandardItem("土木学院"));

    student_model->setItem(1, 0, new QStandardItem("张红"));
    student_model->setItem(1, 1, new QStandardItem("20130202"));
    student_model->setItem(1, 2, new QStandardItem(""));
    student_model->setItem(1, 3, new QStandardItem("18"));
    student_model->setItem(1, 4, new QStandardItem("土木学院"));
}

void Dialog::on_pushButton_searchdev_clicked()
{    
    printf("on_pushButton_searchdev_clicked 1111111111111111111\n");
    QByteArray datagram = "";
    datagram.resize(512);
    printf("on_pushButton_searchdev_clicked 2222222222222222 \n");

    this->remove_tableview_allrow();
    printf("on_pushButton_searchdev_clicked 3333333333333333333 \n");

    for(int i=7;i<datagram.size();i++)
    {
        datagram[i] = 0x00;
    }
    printf("on_pushButton_searchdev_clicked 555555555555555555555 \n");

#if QT_VERSION <= 0x040500 //QT 4.5版本无 insert(int i, const char *s, int len);
	datagram.insert(0, "XXXCID");
#else
	datagram.insert(0, "XXXCID", 6);
#endif
    datagram[6] = (char)0xAA;
    datagram[17] = (char)0xFF;

    //datagram.set
    QHostAddress mcast_addr("238.9.9.1");

#if defined(Q_OS_WIN32) || defined(Q_OS_LINUX)
    int recvbuf = 65535 * 2;

    if ( (::setsockopt(udpSocket->socketDescriptor(), 0, SO_RCVBUF, (const char*)&recvbuf ,sizeof(int)) ) < 0 )
    {
        fprintf(stderr, "Error setting sock opts..\n");
    }
#endif
    printf("on_pushButton_searchdev_clicked 9999999999999999999999 \n");

#if QT_VERSION > 0x040800 //QT 4.8版本加入组播支持
    udpSocket->setSocketOption(QAbstractSocket::MulticastLoopbackOption, 0);//禁止本机接收
    if(udpSocket->joinMulticastGroup(mcast_addr))//这句是关键，加入组播地址
	{		
	}
	else
	{
		QMessageBox::warning(NULL, "warning", "加入组播失败", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
	}
#else
    unsigned char ttl=255;
    if(::setsockopt(udpSocket->socketDescriptor(), IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
    {
        fprintf(stderr, "设置组播TTL错误\n");
    }

    //控制数据是否回送到本地的回环接口,参数loop设置为0禁止回送，设置为1允许回送。
    unsigned char loop=0;
    setsockopt(udpSocket->socketDescriptor(), IPPROTO_IP,IP_MULTICAST_LOOP, &loop, sizeof(loop));

    struct ip_mreq mreq;
    mreq.imr_interface.s_addr = INADDR_ANY;
    mreq.imr_multiaddr.s_addr = inet_addr("238.9.9.1");
    if(setsockopt(udpSocket->socketDescriptor(), IPPROTO_IP,IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1)
    {
        printf("add membership error!");
    }
#endif
    printf("on_pushButton_searchdev_clicked aaaaaaaaaaaaaaaaaaaaaa \n");

    udpSocket->writeDatagram(datagram.data(),datagram.size(), mcast_addr,8300);
    printf("on_pushButton_searchdev_clicked bbbbbbbbbbbbbb \n");

}

void Dialog::on_pushButton_2_clicked()
{
    this->remove_tableview_allrow();
}

void Dialog::on_tableView_doubleClicked(QModelIndex index)
{
    DeviceDetailDialog *dialog = new DeviceDetailDialog(this);
    dialog->setWindowModality(Qt::WindowModal);
    //dialog->show();
    dialog->exec();
}

void Dialog::on_pushButton_3_clicked()
{
    UDPRecvThread *recvThread = new UDPRecvThread();
    recvThread->start();
#if 1
    AVDecodeThread *decodeThread = new AVDecodeThread();
    decodeThread->start();
#endif
}

#if 1
void Dialog::paintEvent(QPaintEvent *pe)
{
#if 1 //(PAINT_IMAGE_MODE==PAINT_IMAGE_QIMAGE)
    QPainter painter(this);
    painter.drawPixmap(0, 0, 800, 480, QPixmap("./images/talk.jpg"));
#endif
}
#endif

void Dialog::on_pushButton_4_clicked()
{
    DeviceDetailDialog *w = new DeviceDetailDialog(this);
    //DeviceDetailDialog w;
    w->show();
}
